package com.foreveross.chameleon.socket;

 
import com.foreveross.chameleon.utils.AppLog;
import com.foreveross.chameleon.utils.PushConstants;
import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;

/**
 * project:
 * author: wzq
 * date: 2014/4/28
 * description:只负责socket通讯,处理收发,与push逻辑无关,push流程 has-a socket
 */
public class SocketConnect {
    private static final String TAG = SocketConnect.class.getSimpleName();
    private static final int MAX_ATTEMPT_TIMES = 3;

    public interface SocketMsgHandler {
        void onReceiveMsg(byte[] msg);
    }

    private SocketMsgHandler msgHandler;
    public void setSocketMsgHandler(SocketMsgHandler msgHandler) {
        this.msgHandler = msgHandler;
    }


    private final String host;
    private final int port;

    private Channel channel;
    private EventLoopGroup group;

    public SocketConnect(String host, int port) {
        this.host = host;
        this.port = port;
    }

    // 使用 保存的ip和端口
    public SocketConnect() {
//        PushPreferences preferences = new PushPreferences();
//        this.host = preferences.getTempHost();
//        this.port = preferences.getTempPort();
        this.host = PushConstants.TEMP_HOST;
        this.port = PushConstants.TEMP_PORT;
    }

    /**
     * 进行连接，该方法会block
     */
    private void connectInternal() {
        AppLog.v(TAG, " initSocketChannel");
        group = new NioEventLoopGroup();
        Bootstrap bootstrap = new Bootstrap();
        bootstrap.group(group);
        bootstrap.channel(NioSocketChannel.class);
        bootstrap.handler(new PushSocketChannelInitializer());
        try {
            channel = bootstrap.connect(host, port)
                    .sync()
                    .channel();
            //AppLog.printProcess("succ");
        } catch(InterruptedException e) {
            e.printStackTrace();
            AppLog.e(TAG,"connectInternal exp\n " + e.getMessage());
            group.shutdownGracefully();
        } catch(Exception e) {
            e.printStackTrace();
            AppLog.e(TAG,"connectInternal exp\n " + e.getMessage());
            group.shutdownGracefully();
        }
    }

    /**
     * 尝试若干次连接,直至超过限制次数 或 成功
     */
    public void connect() {
        // AppLog.whoInvokeMe();
        int i = 0;
        disConnect();
        while(i < MAX_ATTEMPT_TIMES && !isAvailiable()) {
            AppLog.d(TAG,TAG + " connect,尝试次数=" + i);
            connectInternal();
            i++;
        }
        if(isAvailiable()) {
            AppLog.i(TAG,"socket 连接成功");
        } else {
            AppLog.e(TAG,"socket 连接失败");
        }
    }

    /**
     * 判断socket连接是否仍然有效
     *
     * @return true 表示可以进行收发通讯,false的话,需要手动关闭socket
     */
    public boolean isAvailiable() {
        boolean isActive = (channel != null && channel.isActive());
        AppLog.v(TAG,"SocketConnect::isAvailiable =" + isActive);
        return isActive;
    }

    public void disConnect() {
        // AppLog.whoInvokeMe();
        if(channel != null) {
            channel.closeFuture();
            channel = null;
            AppLog.i(TAG,"链接关闭完成");
        }
        if(group != null) {
            group.shutdownGracefully();
            group = null;
        }
    }

    /**
     * 发送消息
     *
     * @param msg 要发送的消息
     *
     * @return 消息是否被正常发送，null 或者 状态不正常时，不能发送消息
     */
    public boolean sendMsg(byte[] msg) {
        if(msg == null) {
            AppLog.e(TAG,"PushSOcket::sendMsg" + " null msg");
            return false;
        }
        if(isAvailiable()) {
            AppLog.i(TAG,">>>>>>>>>>>>PushSocket::sendMsg");
            ByteBuf buf = channel.alloc()
                    .buffer(msg.length);
            buf.writeBytes(msg);
            channel.writeAndFlush(buf);
            return true;
        } else {
            AppLog.e(TAG,"SocketConnect::sendMsg" + " 请求发送消息，但是连接已失效");
            return false;
        }
    }

    /**
     * 初始化socket的channel
     */
    private class PushSocketChannelInitializer extends ChannelInitializer<SocketChannel> {
        @Override
        protected void initChannel(SocketChannel ch) throws Exception {
            ChannelPipeline pipeline = ch.pipeline();
            pipeline.addLast(new SimpleChannelInboundHandler<Object>() {
                @Override
                protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
                    AppLog.v(TAG,TAG + "::channelRead0 >>>>>>>>>>");
                    ByteBuf buf = (ByteBuf) msg;
                    byte[] bytes = new byte[buf.readableBytes()];
                    buf.readBytes(bytes);
                    if(msgHandler != null) {
                        msgHandler.onReceiveMsg(bytes);
                    }
                }

                @Override
                public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
                    cause.printStackTrace();
                    AppLog.e(TAG,"exceptionCaught " + cause.toString());
                    super.exceptionCaught(ctx, cause);
                }

                @Override
                public void channelActive(ChannelHandlerContext ctx) {
                    AppLog.v(TAG,"SocketConnect::channelActive");
                }
            });
        }
    }
}
